大数据面试题:你来讲一下Spark中的血缘关系

您所在的位置:网站首页 hadoop shuffle和spark shuffle 大数据面试题:你来讲一下Spark中的血缘关系

大数据面试题:你来讲一下Spark中的血缘关系

#大数据面试题:你来讲一下Spark中的血缘关系| 来源: 网络整理| 查看: 265

我们知道Spark中的RDD可以从本地集合、外部文件系统创建,从其它RDD转化得到。从其它RDD通过转换算子得到新的RDD,这两个RDD之间具有依赖关系,即血缘。RDD和它依赖的父RDD之间有两种不同的依赖类型,即宽依赖和窄依赖。下面我们具体介绍一下Spark中的血缘关系。

一、血缘关系

RDD只支持粗粒度转换,即在大量记录上执行的单个操作。将创建RDD的一系列Lineage(血统)记录下来,以便恢复丢失的分区。RDD的Lineage会记录RDD的元数据信息和转换行为,当该RDD的部分分区数据丢失时,它可以根据这些信息来重新运算和恢复丢失的数据分区。

代码实现:

object Lineage01 {

def main(args: Array[String]): Unit = {

//1.创建SparkConf并设置App名称

val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

//2.创建SparkContext,该对象是提交Spark App的入口

val sc: SparkContext = new SparkContext(conf)

//3.加载数据进行并进行数据转换

val rdd: RDD[String] = sc.makeRDD(List("hello world", "hello spark"))

val wordRDD: RDD[String] = rdd.flatMap(_.split(" "))

val mapRDD: RDD[(String, Int)] = wordRDD.map((_,1))

val resultRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)

//4.打印RDD之间的血缘关系

println(resultRDD.toDebugString)

//5.触发计算

resultRDD.collect()

//6.关闭连接

sc.stop()

}

}

查看运行结果:

结果说明:圆括号中的数字12表示RDD的并行度,也就是有几个分区,[0]是第一步操作,创建集合RDD,[1]是第二步操作,执行flatMap算子,[2]是第三步操作,执行map算子,[3]是第四步操作,执行reduceByKey算子,因reduceByKey算子存在Shuffle过程,所以结果前面缩进显示,代表新的stage划分。血缘关系将RDD的一系列操作记录下来,当该RDD的部分分区数据丢失时,它可以根据这些信息来重新运算和恢复丢失的数据分区。

二、依赖关系

理解RDD是如何工作的,最重要的就是理解Transformations。RDD之间的关系可以从以下角度来理解,RDD是从哪些RDD转换而来,RDD依赖于父RDD的哪些Partition,这种关系就是RDD之间的依赖。

代码实现:

object Lineage02 {

def main(args: Array[String]): Unit = {

//1.创建SparkConf并设置App名称

val conf: SparkConf = new SparkConf().setAppName("SparkCoreTest").setMaster("local[*]")

//2.创建SparkContext,该对象是提交Spark App的入口

val sc: SparkContext = new SparkContext(conf)

//3.打印RDD之间的依赖关系

val rdd: RDD[String] = sc.makeRDD(List("hello world","hello spark"))

println(rdd.dependencies)

println("----------------------")

val wordRDD: RDD[String] = rdd.flatMap(_.split(" "))

println(wordRDD.dependencies)

println("----------------------")

val mapRDD: RDD[(String, Int)] = wordRDD.map((_,1))

println(mapRDD.dependencies)

println("----------------------")

val resultRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)

println(resultRDD.dependencies)

//4.触发计算

resultRDD.collect()

//5.查看localhost:4040页面,观察DAG图

Thread.sleep(1000000)

//6.关闭连接

sc.stop()

}

}

查看运行结果:

结果说明:第一步从集合中创建RDD,不是从其它RDD转换而来,没有RDD之间的依赖关系,所以执行sc.makeRDD打印依赖关系结果为List(),而后的flatMap算子和map算子对RDD进行数据转换操作,每一个父RDD的分区最多被子RDD的一个分区使用,所以依赖结果是OneToOneDependency,而reduceByKey,同一个父RDD的分区被多个子RDD的分区依赖,是一对多的关系,会引起Shuffle,所以依赖结果是ShuffleDependency。

查看DAG图:

注意:RDD和它依赖的父RDD的依赖关系有两种不同的类型,即窄依赖(NarrowDependency)和宽依赖(ShuffleDependency)。

窄依赖:窄依赖表示每一个父RDD的Partition最多被子RDD的一个Partition使用,是一对一或者多对一的关系。如下图所示:

宽依赖:宽依赖表示同一个父RDD的Partition被多个子RDD的Partition依赖,是一对多的关系,会引起Shuffle。如下图所示:

三、总结

通过这篇文章,大家对Spark RDD的血缘关系是不是有进一步的了解了,RDD的血缘关系是Spark的容错机制之一,当某个RDD的部分分区数据丢失时,它可以根据血缘关系来重新运算,以恢复丢失的数据分区。



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3